home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
001a
/
mskrmsrc.zip
/
MSNARP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-24
|
12KB
|
455 lines
/* File MSNARP.C
* ARP and RARP packet processor
*
* Copyright (C) 1991, University of Waterloo.
* Copyright (C) 1991, Trustees of Columbia University in the
* City of New York. Permission is granted to any individual or
* institution to use, copy, or redistribute this software as long as
* it is not sold for profit and this copyright notice is retained.
*
* Original version created by Erick Engelke of the University of
* Waterloo, Waterloo, Ontario, Canada.
* Adapted and modified for MS-DOS Kermit by Joe R. Doupnik,
* Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
*
* Last edit
* 6 Sept 1991
*
* Address Resolution Protocol
*
* Externals:
* ap_handler(pb) - returns 1 on handled correctly, 0 on problems
* arp_resolve - rets 1 on success, 0 on fail
* - does not return hardware address if passed NULL for buffer
*
*/
#include "msntcp.h"
#include "msnlib.h"
#ifdef KERMIT
#define MAX_ARP_DATA 10
#else
#define MAX_ARP_DATA 40
#define NEW_EXPIRY
#endif /* KERMIT */
#define MAX_ARP_ALIVE 300 /* five minutes */
#define MAX_ARP_GRACE 100 /* additional grace upon expiration */
eth_address eth_none = { 0,0,0 };
typedef struct
{
longword ip;
eth_address hardware;
byte flags;
byte bits; /* bits in network */
longword expiry;
} arp_tables;
typedef struct
{
longword gate_ip;
longword subnet;
longword mask;
} gate_tables;
#define ARP_FLAG_NEED 0
#define ARP_FLAG_FOUND 1
#define ARP_FLAG_FIXED 255 /* cannot be removed */
extern longword ipbcast; /* IP broadcast address */
/*
* arp resolution cache - we zero fill it to save an initialization routine
*/
static arp_tables arp_data[MAX_ARP_DATA];
gate_tables arp_gate_data[MAX_GATE_DATA];
word arp_last_gateway = 0;
static word arp_index = 0; /* rotates round-robin */
void
arp_init() /* init to zero ARP and arp_gateway tables */
{
static first_time = 0;
if (first_time == 0)
{
memset((byte *)arp_data, 0, sizeof(arp_tables) * MAX_ARP_DATA);
memset((byte *)arp_gate_data, 0,
sizeof(gate_tables) * MAX_GATE_DATA);
}
arp_last_gateway = 0; /* reset the gateway table */
first_time = 1; /* to keep arp_tables on hot start */
}
/*
* arp_add_gateway - if data is NULL, don't use string
*/
void
arp_add_gateway(byte *data, longword ip)
{
int i;
register byte *subnetp, *maskp;
longword subnet, mask;
if ((data == NULL) && (ip == 0L)) return; /* nothing to do */
subnet = mask = 0;
if (data != NULL)
{
maskp = NULL;
if ((subnetp = strchr(data, ',')) != NULL)
{
*subnetp++ = 0;
if (maskp = strchr(subnetp, ','))
{
*maskp++ = 0;
mask = aton(maskp);
subnet = aton(subnetp);
}
else
{
subnet = aton(subnetp);
switch (i = (subnet >> 30) & 0x000f)
{
case 0:
case 1: mask = 0xff000000L; break;
case 2: mask = 0xfffffe00L; break;
case 3: mask = 0xffffff00L; break;
}
}
}
}
if (arp_last_gateway >= MAX_GATE_DATA) return;
for (i = 0; i < arp_last_gateway; i++)
if (arp_gate_data[i].mask < mask)
{
bcopy(&arp_gate_data[i], &arp_gate_data[i+1],
(arp_last_gateway - i) * sizeof(gate_tables));
break;
}
if ((data != NULL) && (ip == 0L)) /* if text form given */
ip = aton(data); /* convert to 32 bit long */
arp_gate_data[i].gate_ip = ip;
arp_gate_data[i].subnet = subnet;
arp_gate_data[i].mask = mask;
arp_last_gateway++; /* used up another one */
}
longword
arp_rpt_gateway(int i) /* report IP of gateway i */
{
if (i >= 0 && i < MAX_GATE_DATA)
return (arp_gate_data[i].gate_ip);
else return (0L);
}
static void
arp_request(longword ip)
{
register arp_Header *op;
op = (arp_Header *)eth_formatpacket(ð_brdcast[0], 0x0608);
op->hwType = arp_TypeEther;
op->protType = 0x0008; /* IP Ethertype*/
op->hwProtAddrLen = sizeof(eth_address) + (sizeof(longword) << 8);
op->opcode = ARP_REQUEST;
op->srcIPAddr = intel(my_ip_addr);
bcopy(eth_addr, op->srcEthAddr, sizeof(eth_address));
op->dstIPAddr = intel(ip);
eth_send(sizeof(arp_Header)); /* send the packet */
}
static arp_tables *
arp_search(longword ip, int create)
{
register int i;
register arp_tables *arp_ptr;
for (i = 0; i < MAX_ARP_DATA; i++)
if (ip == arp_data[i].ip)
return(&arp_data[i]);
/* didn't find any */
if (create != 0)
{ /* pick an old or empty one */
for (i = 0; i < MAX_ARP_DATA; i++)
{
arp_ptr = &arp_data[i];
if ((arp_ptr->ip == 0L) ||
chk_timeout(arp_ptr->expiry + MAX_ARP_GRACE))
return(arp_ptr);
}
/* pick one at pseudo-random */
return (&arp_data[arp_index =
(arp_index + 1) % MAX_ARP_DATA]);
}
return (NULL);
}
void
arp_register(longword use, longword instead_of)
{
register arp_tables *arp_ptr;
if (arp_ptr = arp_search(instead_of, 0))
{ /* now insert the address of the new guy */
arp_ptr->flags = ARP_FLAG_NEED;
arp_resolve(use, arp_ptr->hardware);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
return;
}
arp_ptr = arp_search(use, 1); /* create a new one */
arp_ptr->flags = ARP_FLAG_NEED;
arp_ptr->ip = instead_of;
arp_resolve(use, arp_ptr->hardware);
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
}
void
arp_tick(longword ip)
{
register arp_tables *arp_ptr;
if (arp_ptr = arp_search(ip, 0))
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
}
/*
* arp_handler - handle incomming ARP packets
*/
int
arp_handler(arp_Header *in)
{
register arp_Header *op;
longword his_ip;
register arp_tables *arp_ptr;
int i;
if (in == NULL) return (0); /* failure */
if (in->hwType != arp_TypeEther || /* have Ethernet hardware */
in->protType != 0x0008) /* and Internet software */
return(0); /* 0 means no, fail */
/* continuously accept data - but only for people we talk to */
his_ip = intel(in->srcIPAddr);
if ((arp_ptr = arp_search(his_ip, 0)) != NULL)/* do not create entry */
{
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
bcopy(in->srcEthAddr, arp_ptr->hardware, sizeof(eth_address));
arp_ptr->flags = ARP_FLAG_FOUND;
}
/* does someone else want our Ethernet address ? */
if (in->opcode == ARP_REQUEST && /* and be a resolution req */
in->dstIPAddr == intel(my_ip_addr)) /* for my address */
{
op = (arp_Header *)eth_formatpacket(in->srcEthAddr, 0x0608);
op->hwType = arp_TypeEther;
op->protType = 0x0008; /* IP Ethertype */
op->hwProtAddrLen = sizeof(eth_address) +
(sizeof(longword) << 8);
op->opcode = ARP_REPLY;
op->dstIPAddr = in->srcIPAddr;
op->srcIPAddr = in->dstIPAddr;
bcopy(eth_addr, op->srcEthAddr, sizeof(eth_address));
bcopy(in->srcEthAddr, op->dstEthAddr, sizeof(eth_address));
return (eth_send(sizeof(arp_Header)));
}
return (1); /* for success */
}
/*
* arp_resolve - resolve IP address to hardware address
*/
int
arp_resolve(longword ina, eth_address *ethap)
{
register arp_tables *arp_ptr;
register int i;
int j;
longword timeout, resend;
static int recurse = 0;
if (pktdevclass == PD_SLIP)
/* we are running slip or somthing which does not use addresses */
return(1);
if (ina == my_ip_addr)
{
if (ethap != NULL)
bcopy(eth_addr, ethap, sizeof(eth_address));
recurse = 0;
return(1); /* success */
}
if (ina == 0L || ina == 0xffffffffL || ina == ipbcast)
return (0); /* cannot resolve IP of 0's or 0xff's*/
if (recurse > 6) return (0); /* fail */
recurse++;
/* attempt to solve with ARP cache */
while (arp_ptr = arp_search(ina, 0))
{
if (strncmp(arp_ptr->hardware, eth_none, sizeof(eth_address)))
{
/* has been resolved */
#ifdef NEW_EXPIRY
if (chk_timeout(arp_ptr->expiry))
{
if (! chk_timeout(arp_ptr->expiry +
MAX_ARP_GRACE))
/* we wish to refresh it asynchronously */
arp_request(ina);
else
break; /* must do full fledged arp */
}
#endif /* NEW_EXPIRY */
if ((arp_ptr->flags == ARP_FLAG_FOUND) ||
(arp_ptr->flags == ARP_FLAG_FIXED))
{
/* we found a valid hardware address */
if (ethap != NULL)
{
bcopy(arp_ptr->hardware, ethap,
sizeof(eth_address));
recurse = 0;
return(1); /* success */
}
} /* end of if ((arp_ptr... */
} /* end of if (strncmp... main */
else break;
} /* end of while */
/* make a new one if necessary */
if (arp_ptr == NULL)
{
arp_ptr = arp_search(ina, 1); /* 1 means create an entry */
arp_ptr->flags = ARP_FLAG_NEED; /* say need a real entry */
}
/* we must look elsewhere - but is it on our subnet? */
if ((ina ^ my_ip_addr) & sin_mask) /* not of this network */
{
j = 0; /* init status return */
for (i = 0; i < arp_last_gateway; i++)
{ /* compare the various subnet bits */
if ((arp_gate_data[i].mask & ina) ==
arp_gate_data[i].subnet)
/* watch out RECURSIVE CALL! */
if ((j = arp_resolve(arp_gate_data[i].gate_ip,
ethap)) != 0)
break; /* success */
}
recurse--;
return (j);
}
if (ina == 0L) /* return if no host, or no gateway */
{
recurse--;
outs("\r\n Cannot find a gateway");
return(0); /* fail */
}
/* is on our subnet, we must resolve */
timeout = set_timeout(2); /* two seconds is long for ARP */
while (!chk_timeout(timeout))
{ /* do the request */
arp_request(arp_ptr->ip = ina);
resend = set_timeout(1) - 14L; /* 250 ms */
while (!chk_timeout(resend))
{
tcp_tick(NULL); /* read packets */
if (arp_ptr->flags)
{
if (ethap != NULL)
bcopy(arp_ptr->hardware, ethap,
sizeof(eth_address));
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
recurse = 0;
return(1); /* success */
}
}
}
recurse--;
return(0); /* fail */
}
int
rarp_handler(arp_Header *in)
{
register int i;
longword his_ip;
register arp_tables *arp_ptr;
if (in == NULL) return (0); /* failure */
/* require Ethernet hardware and Internet software */
if ((in->hwType != arp_TypeEther) /* || (in->protType != 0x0008)*/)
return (0); /* 0 means no, fail */
his_ip = intel(in->srcIPAddr);
if ((arp_ptr = arp_search(his_ip, 0)) != NULL)
{
arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
bcopy(in->srcEthAddr, arp_ptr->hardware, sizeof(eth_address));
arp_ptr->flags = ARP_FLAG_FOUND;
}
/* look for RARP Reply */
if ((my_ip_addr == 0) && (in->opcode == RARP_REPLY))
{ /* match our Ethernet address too */
for (i = 0; i < sizeof(eth_address); i++)
if (in->dstEthAddr[i] != eth_addr[i])
return (1); /* not for us */
my_ip_addr = intel(in->dstIPAddr); /* our IP addr */
}
return (1); /* for success */
}
/* send a RARP packet to request an IP address for our Ethernet address */
static void
arp_rev_request(void)
{
register arp_Header *op;
op = (arp_Header *)eth_formatpacket(ð_brdcast[0], 0x3580); /*RARP */
op->hwType = arp_TypeEther;
op->protType = 0x0008; /* IP Ethertype */
op->hwProtAddrLen = sizeof(eth_address) + (sizeof(longword) << 8);
op->opcode = RARP_REQUEST;
op->srcIPAddr = 0L; /* we have no IP */
bcopy(eth_addr, op->srcEthAddr, sizeof(eth_address));
op->dstIPAddr = 0L;
bcopy(eth_addr, op->dstEthAddr, sizeof(eth_address));
eth_send(sizeof(arp_Header)); /* send the packet */
}
/* Send a series of RARP requests until our IP address is non-zero or
we timeout.
*/
int
do_rarp(void)
{
longword timeout, resend;
timeout = set_timeout(10); /* 10 seconds total */
while (chk_timeout(timeout) == 0)
{
arp_rev_request(); /* ask for our IP */
resend = set_timeout(1); /* two second retry */
while (chk_timeout(resend) == 0)
{
tcp_tick(NULL); /* read packets */
if (my_ip_addr != 0L) return (1); /* got a reply */
}
}
return (0); /* got no reply */
}